<template>
  <div class="table-wrapper" ref="tableWrapper">
    <div class="table-header">
      <div class="left">
        <div class="title">
          <template v-if="props.tableIcon.includes('iconfont')">
            <ElIcon :class="props.tableIcon" />
          </template>
          <template v-if="props.tableIcon">
            <ElIcon>
              <component :is="props.tableIcon" />
            </ElIcon>
          </template>
          <span v-if="props.tableName">
            {{ props.tableName }}
          </span>
          <ElTooltip v-if="props.help" placement="top" :content="props.help">
            <ElIcon>
              <Warning />
            </ElIcon>
          </ElTooltip>
        </div>
      </div>
      <div class="right">
        <div>
          <ElButton type="primary">Click</ElButton>
        </div>
        <span class="split"></span>
        <ElButtonGroup :disabled="loading" class="toolbar">
          <template v-for="item in props.toolbar.split(',')">
            <component :is="toolsList[item]" />
          </template>
        </ElButtonGroup>
      </div>
    </div>
    <div
      class="table-body"
      :class="[
        props.headerNoWrap ? 'table-header__nowrap' : '',
        `header-title_${props.titleDirection}`,
        props.showPagination ? '' : 'no-pagination',
      ]"
    >
      <ElTable
        ref="tableRef"
        :height="maxHeight"
        border
        v-loading="loading"
        v-bind="attrs"
        @sort-change="handleSortChange"
        :data="sourceData"
      >
        <!-- 索引列 -->
        <ElTableColumn
          v-if="props.index"
          fixed="left"
          type="index"
          width="50"
          label="#"
          :index="typeof props.index === 'function' ? props.index : handleIndex"
        ></ElTableColumn>
        <!-- 选择列 -->
        <ElTableColumn
          v-if="props.selection"
          :selectable="
            typeof props.selection === 'function' ? props.selection : null
          "
          type="selection"
          width="40"
        />
        <!-- 展开列 -->
        <ElTableColumn
          v-if="props.expand"
          fixed="left"
          type="expand"
          width="40"
        >
          <template #default="scope">
            <slot name="expand" v-bind="scope"></slot>
          </template>
        </ElTableColumn>
        <!-- 内容主体 -->
        <template
          v-for="(item, index) in internalColumns"
          :key="item.tableColumn.prop || index"
        >
          <TableColumn :columnProps="item" :tableColumnSlots="slots" />
        </template>
        <!-- 操作列 -->
        <ElTableColumn
          v-if="slots.actions || props.actions.length"
          :label="$t('common.Actions')"
          :width="props.actionsWidth"
          :fixed="props.actionsFixed"
        >
          <template #default="scope">
            <div class="actions">
              <slot name="actions" v-bind="scope">
                <ElButton
                  v-for="(item, index) in props.actions"
                  :key="index"
                  v-bind="item"
                  @click="item.handler(scope, item, index)"
                >
                  {{ item.label }}
                </ElButton>
              </slot>
              <!-- 两者都存在 -->
              <ElDropdown
                v-if="$slots.actions && props.actions.length"
                @command="(c) => handleCommand(c, scope)"
              >
                <ElButton icon="MoreFilled" link></ElButton>
                <template #dropdown>
                  <ElDropdownMenu>
                    <ElDropdownItem
                      v-for="(item, index) in props.actions"
                      :key="index"
                      :command="item"
                      v-bind="item"
                      >{{ item.label }}</ElDropdownItem
                    >
                  </ElDropdownMenu>
                </template>
              </ElDropdown>
            </div>
          </template>
        </ElTableColumn>
        <!-- el-table原生插槽 -->
        <template slot="empty">
          <slot name="empty"></slot>
        </template>
        <template slot="append">
          <slot name="append"></slot>
        </template>
      </ElTable>
      <ElPagination
        v-if="props.showPagination"
        ref="paginationRef"
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        hide-on-single-page
        background
        :total="total"
        :page-sizes="props.pageSize"
        :layout="`jumper,prev,pager,next,${
          props.customPageSize ? 'slot' : 'sizes'
        },total`"
      >
        <template #default>
          <ElSelect
            v-model="customSize"
            allow-create
            filterable
            default-first-option
            @change="handlePageSizeChange"
          >
            <ElOption
              v-for="item in props.pageSize"
              :key="item"
              :label="`${item}${$t('elementPlus.Rows')}/${$t(
                'elementPlus.Page'
              )}`"
              :value="item"
            >
            </ElOption>
          </ElSelect>
        </template>
      </ElPagination>
    </div>
  </div>
</template>

<script setup lang="jsx">
import {
  computed,
  onMounted,
  onUnmounted,
  ref,
  useAttrs,
  useSlots,
  useTemplateRef,
  watch,
} from "vue";
import {
  buildTableProps,
  tableEmits,
  injectConfig,
  normalizeProps,
} from "./index";
import { debounce, elToggleFullScreen } from "@/utils";
import TableColumn from "./TableColumn.vue";
defineOptions({
  inheritAttrs: false, // 不继承组件上的attrs属性
  name: "Table",
});
let ob = null; // ResizeObserver实例
let tableScrollbarWrap = null; // 表格滚动容器 用于翻页自动滚动到顶部
const props = defineProps(buildTableProps());
const emits = defineEmits(tableEmits);
const attrs = useAttrs();
const slots = useSlots();
const tableWrapper = useTemplateRef("tableWrapper");
const pagination = useTemplateRef("paginationRef");
const table = useTemplateRef("tableRef");
const maxHeight = ref(null); // 最大高度 没有传入自动计算
const currentPage = ref(1); // 当前页码
const pageSize = ref(30); // 每页条数
const customSize = ref(pageSize.value); // 自定义页码大小
const loading = ref(false); // 是否加载中
const tableData = ref([]); // 数据源
const requestTotal = ref(0); // 请求总数
const total = computed(() => {
  if (props.fetchData) {
    return requestTotal.value;
  } else {
    return attrs.data?.length ?? 0;
  }
});
const sourceData = computed(() => {
  if (props.fetchData) {
    return tableData.value;
  }
  const page = currentPage.value;
  const size = pageSize.value;
  const data = attrs.data || [];
  return props.showPagination
    ? data.slice((page - 1) * size, page * size) || []
    : data;
});

// 内部使用的列 通过props.columns处理
const internalColumns = ref([]);
// 工具栏 使用props.toolbar更改顺序和显示/隐藏
const toolsList = {
  download: () => (
    <ElButton
      icon="Download"
      onClick={() => handleToolsClick("download")}
      disabled={loading.value}
    ></ElButton>
  ),
  refresh: () => (
    <ElButton
      onClick={() => handleToolsClick("refresh")}
      disabled={loading.value}
    >
      <ElIcon
        className={`iconfont icon-shuaxin ${
          loading.value ? "rotate-loading" : ""
        }`}
      ></ElIcon>
    </ElButton>
  ),
  fullscreen: () => (
    <ElButton
      icon="FullScreen"
      onClick={() => handleToolsClick("fullScreen")}
      disabled={loading.value}
    ></ElButton>
  ),
  columnSetting: () => (
    <ElPopover
      placement="bottom"
      width={300}
      trigger="click"
      v-slots={{
        reference: () => (
          <ElButton icon="Grid" disabled={loading.value}></ElButton>
        ),
        default: () => (
          <div className="drag-column">
            <ElTree
              data={internalColumns.value}
              props={{
                label: (data) =>
                  data.tableColumn.label || data.tableColumn.prop,
              }}
              draggable
              default-expand-all
              node-key="prop"
              v-slots={{
                default: ({ data }) => (
                  <ElCheckbox
                    v-model={data.visible}
                    label={data.tableColumn.label || data.tableColumn.prop}
                  />
                ),
              }}
            ></ElTree>
          </div>
        ),
      }}
    ></ElPopover>
  ),
};
if (props.fetchData && !props.initNotRequest) {
  fetchData(true);
}
// 列设置改变
watch(
  () => props.columns,
  (newProps) => {
    const items = [];
    for (const item of newProps) {
      // 处理传入的属性 将自定义属性和原生ElementPlus属性隔离
      const newItem = normalizeProps(item);
      items.push(newItem);
    }
    internalColumns.value = items;
  },
  {
    immediate: true,
    deep: true,
  }
);
// 页码 页容量改变
watch([currentPage, pageSize], ([newPage, newSize], [oldPage, oldSize]) => {
  emits("pageChange", newPage, newSize);
  if (newPage === oldPage && newSize !== oldSize) {
    fetchData(true); // 重置页码
  } else {
    fetchData();
  }
});
onMounted(() => {
  // 没有传入高度
  if (!attrs.maxHeight && !attrs.height && !attrs["max-height"]) {
    ob = new ResizeObserver(debounce(handleResizeObserver));
    ob.observe(tableWrapper.value);
  }
  if (!tableScrollbarWrap) {
    tableScrollbarWrap = table.value.$el.querySelector(
      ".el-table__body-wrapper .el-scrollbar__wrap"
    );
  }
});
onUnmounted(() => {
  if (ob) {
    ob.disconnect();
  }
});
// 监听表格容器变化 响应式表格
function handleResizeObserver() {
  const vh = props.relativeEle
    ? props.relativeEle?.clientHeight
    : window.innerHeight;
  const tableRef = table.value;
  const paginationRef = pagination.value;
  if (props.showPagination ? !paginationRef?.$el : false || !tableRef?.$el) {
    return;
  }
  const paginationHeight = props.showPagination
    ? paginationRef.$el.offsetHeight
    : 0;

  const top =
    (props.relativeEle
      ? tableRef.$el.offsetTop
      : tableRef.$el.getBoundingClientRect().top) || 0;
  let tableHeight = vh - paginationHeight - top - 10;
  tableHeight =
    tableHeight < injectConfig.value.minHeight
      ? injectConfig.value.minHeight
      : tableHeight;
  maxHeight.value = tableHeight;
}
function handleIndex(index) {
  return index + 1 + (currentPage.value - 1) * pageSize.value;
}
/**
 * 查询数据
 * @param isPageChange 是否是分页切换 手动查询需要返回第一页
 */
async function fetchData(isPageChange = false, searchForm = {}) {
  if (!props.fetchData) {
    return;
  }
  if (loading.value) {
    return;
  }
  try {
    loading.value = true;
    if (isPageChange) {
      currentPage.value = 1;
    }
    emits("getTableDataBefore", currentPage.value, pageSize.value);
    const res = await props.fetchData(
      currentPage.value,
      pageSize.value,
      searchForm
    );
    emits("getTableDataAfter", res);
    tableData.value = res?.list ?? [];
    requestTotal.value = res?.total ?? 0;
    if (tableScrollbarWrap) {
      tableScrollbarWrap.scrollTo({
        top: 0,
        behavior: "smooth",
      });
    }
  } catch (error) {
    throw error;
  } finally {
    loading.value = false;
  }
}

async function handleSortChange({ column, prop, order }) {
  if (props.fetchData) {
    // TODO 排序时不一定需要请求？如：在 SearchTable 中 需要优化
    await fetchData(true, { prop, order });
    attrs.sortChange({ column, prop, order });
  } else {
    attrs.sortChange({ column, prop, order });
  }
}

// 自定义页容量改变
function handlePageSizeChange(val) {
  pageSize.value = +val;
}
// 表格自带工具按钮点击
function handleToolsClick(type) {
  switch (type) {
    case "fullScreen":
      elToggleFullScreen(tableWrapper.value);
      break;
    case "download":
      // 导出表格
      break;
    case "refresh":
      fetchData();
      break;
  }
}

function handleCommand(item, scope) {
  const clickItem = item.command
    ? props.actions.find((v) => v.command === item.command)
    : item;
  if (clickItem && clickItem.handler) {
    clickItem.handler(scope, clickItem);
  }
}

defineExpose({
  fetchData, // 手动触发请求
  resize: handleResizeObserver, // 手动触发计算大小函数
});
</script>

<style scoped src="./index.css"></style>
